ConquerMe II: The Lost Princess
by MisterE


Tutorial by Lucifer48 [Immortal Descendants]
(August 8th, 1999)


Contents:
Battle One: One yer Way!
Battle Two: The Tower
The Final Battle: The Princess
Conclusion & Greetings


Battle One: One yer Way!

XXXX:004015E5  CALL USER32!SendDlgItemMessageA  ;(WM_GETTEXTLENGTH)
XXXX:004015EA  CMP  EAX,10                      ;16 chars for the serial
...                                             ;(the 16th char of the serial is not used)
XXXX:00401602  CMP  EAX,08
XXXX:00401605  JAE  0040161B                    ;8 chars minimum for the name (otherwise ..
...                                             ; .. add null chars to arrive at 8 chars)
XXXX:0040161B  CALL 004012DE                    ;protection scheme
XXXX:00401620  PUSH 004044A8                    ;11111111
XXXX:00401625  PUSH 004044E2                    ;8 numbers (crypted)
XXXX:0040162A  CALL KERNEL32!lstrcmp            ;comparaison
XXXX:0040162F  OR   EAX,EAX
The call 004012DE is made by few following loops. Let's note X0, X1, X2, ..., Xe the 15 chars of the serial; and N0, N1, ..., N7 the 8 chars of the name.

This is the first loop:
XXXX:00401353  PUSH ECX                         ;LOOP #1 (ecx is the index of the loop)
XXXX:00401354  MOV  AL,[ECX+004046E3]           ;read X0, X1, ..., X7
XXXX:0040135A  MOV  DL,[ECX+00404AE5]           ;read N0, N1, ..., N7
XXXX:00401360  SUB  AX,DX
XXXX:00401363  MOV  DL,[ECX+00404AF4]           ;read X7, X9, ..., Xe
XXXX:00401369  SUB  AX,DX
XXXX:0040136C  ADD  AX,012C
XXXX:00401370  MOV  BL,0A
XXXX:00401372  CWD
XXXX:00401374  IDIV BX
XXXX:00401377  ADD  ESI,EDX                     ;esi will contain a sort of checksum
XXXX:00401379  OR   DL,30
XXXX:0040137C  POP  ECX
XXXX:0040137D  MOV  [ECX+0040449F],DL           ;write the final char
XXXX:00401383  INC  ECX
XXXX:00401384  CMP  ECX,08
XXXX:00401387  JNZ  00401353
This loop makes a pretty serial of 8 chars (let's note it S0, S1, ..., S7).
  (X0 - N0 - X7 + 12Ch) mod Ah
+ (X1 - N1 - X8 + 12Ch) mod Ah
+  ...
+ (X7 - N7 - Xe + 12Ch) mod Ah
-------------------------------
= ESI
We continue:
XXXX:004013B2  MOV  DL,[004046E3]               ;read X0
XXXX:004013B8  AND  DL,0F
XXXX:004013BB  ADD  ESI,EDX                     ;definitive value for esi
XXXX:004013BD  XOR  EDX,EDX
XXXX:004013BF  MOV  EAX,ESI
XXXX:004013C1  MOV  CL,08
XXXX:004013C3  CWD
XXXX:004013C5  IDIV CX
XXXX:004013C8  XOR  ESI,ESI
The result (of mod) is in EDX, et will disturb the copy of the string X0, X1, ..., X7; it will do that:
XXXX:004013CC  MOV  AL,[ESI+004046E3]           ;read X0, X1, X2, ..., X7
XXXX:004013D2  MOV  [EDX+004044E2],AL           ;copy (in a wrong order)
XXXX:004013D8  INC  EDX
XXXX:004013D9  CMP  EDX,08
XXXX:004013DC  JNZ  004013E3
XXXX:004013DE  MOV  EDX,00000000
XXXX:004013E3  INC  ESI
XXXX:004013E4  CMP  ESI,08
XXXX:004013E7  JNZ  004013CC
Example: EDX=5, then
X0 X1 X2 X3 X4 X5 X6 X7 ==[become]==> X3 X4 X5 X6 X7 X0 X1 X2

We continue:
XXXX:004013F5  PUSH ECX                         ;LOOP #2
XXXX:004013F6  XOR  EDX,EDX
XXXX:004013F8  XOR  EAX,EAX
XXXX:004013FA  MOV  DL,[ECX+0040449F]           ;read S0, S1, ..., S7
XXXX:00401400  SUB  AX,DX
XXXX:00401403  ADD  AX,012C
XXXX:00401407  MOV  BL,0A
XXXX:00401409  CWD
XXXX:0040190B  IDIV BX
XXXX:0040140E  MOV  AL,[ECX+004044E2]           ;read X0, X1, ..., X7 (in the WRONG order)
XXXX:00401414  AND  AL,0F
XXXX:00401416  ADD  AL,0A
XXXX:00401418  SUB  AL,DL
XXXX:0040141A  CMP  AL,09
XXXX:0040141C  JBE  00401420
XXXX:0040141E  SUB  AL,0A
XXXX:00401420  OR   AL,30
XXXX:00401422  MOV  [ECX+004046E3],AL           :we will obtain 8 numbers again
XXXX:00401428  POP  ECX                         ;let's note it T0, T1, ..., T7
XXXX:00401429  INC  ECX
XXXX:0040142A  CMP  ECX,08
XXXX:0040142D  JNZ  004013F5
The next boucle is exactly the same as the LOOP #1 except, that T0, T1, ...T7 are read (instead of N0, N1, ..., N7):
XXXX:00401439  PUSH ECX
XXXX:0040143A  MOV  AL,[ECX+004044E2]           ;read X0, X1, ..., X7 (in the WRONG order)
XXXX:00401440  MOV  DL,[ECX+004046E3]           ;read T0, T1, ..., T7
XXXX:00401446  SUB  AX,DX
XXXX:00401449  MOV  DL,[ECX+00404AF4]           ;read X7, X9, ..., Xe
...
exactly the same as the LOOP #1
...
XXXX:00401463  MOV  [ECX+004044E2],DL           ;we'll get again 8 numbers
XXXX:00401469  INC  ECX                         ;let's note it U0, U1, ..., U7
XXXX:0040146A  CMP  ECX,08
we continue...
...                                             ;few unused lines...
XXXX:00401498  MOV  DL,[004044E2]               ;read U0
XXXX:0040149E  AND  DL,0F
XXXX:004014A1  ADD  ESI,EDX                     ;same method as above
XXXX:004014A3  XOR  EDX,EDX
XXXX:004014A5  MOV  EAX,ESI                     ;re-use the ckecksum of the previous loop
XXXX:004014A7  MOV  CL,08
XXXX:004014A9  CWD
XXXX:004014AB  IDIV CX				;edx= eax mod 8
XXXX:004014AE  XOR  ESI,ESI
The remainder (of the division) will be used (exactly as above)...
XXXX:004014B2  MOV  AL,[ESI+004044E2]           ;read U0, U1, ..., U7
XXXX:004014B8  MOV  [EDX+004046E3],AL           ;copy (in a WRONG order)
XXXX:004014BE  INC  EDX                         ;(same thing as above...)
XXXX:004014BF  CMP  EDX,08
XXXX:004014C2  JNZ  004014C9
XXXX:004014C4  MOV  EDX,00000000
XXXX:004014C9  INC  ESI
XXXX:004014CA  CMP  ESI,08
XXXX:004014CD  JNZ  004014B2
The last loop:
XXXX:004014DB  PUSH ECX                         ;exactly the same as the LOOP #2
...
XXXX:004014E0  MOV  DL,[ECX+00404AF4]           ;read X7, X9, ..., Xe
...
XXXX:004014F4  MOV  AL,[ECX+004046E3]           ;read U0, U1, ..., U7 (in a WRONG order)
...
XXXX:00401508  MOV  [ECX+004044E2],AL           ;our 8 final chars (*)
XXXX:0040150E  POP  ECX
XXXX:0040150F  INC  ECX                         ;next loop
XXXX:00401510  CMP  ECX,08
XXXX:00401513  JNZ  004014DB
(*) This number is compared to 11111111.
Let's find now a valid serial... Each chars are independant, it is will be easier for us.

This is what we must find for the first char (X0):
L1:    {   ( (X0 - N0 - X7 +12C ) mod Ah ) OR 30h = S0
L2:    {   ( ( (X0' AND F) + Ah ) - ( (-S0 + 12C) mod Ah ) ) OR 30h = T0     (**)
L3:    {   ( (X0' - T0 - X7 + 12C) mod A ) OR 30h = U0
L4:    {   ( ( (U0' AND F) + Ah ) - ( (-X7 + 12C) mod Ah ) ) OR 30h = 31h    (***)
Remark: I've written X0', the X0 byte after the re-ordering/copy loop (in XXXX:004013CC), same thing for U0'.
(see XXXX:004014AB and XXXX:004013C5).

(**): Don't forget that if T0>39h then T0=T0-Ah; same thing for (***).

Let's analyse the fourth line (L4):
we must have ((U0' AND F) + Ah) - ((-X7 + 12C) mod Ah) = 1. Without forgetting the condition (**), we have six possibilities:
    (U0' AND F) + Ah) = Fh  and  ((-X7 + 12C) mod Ah) = 4
or  (U0' AND F) + Ah) = Eh  and	 ((-X7 + 12C) mod Ah) = 3
or  (U0' AND F) + Ah) = Dh  and	 ((-X7 + 12C) mod Ah) = 2
or  (U0' AND F) + Ah) = Ch  and	 ((-X7 + 12C) mod Ah) = 1
or  (U0' AND F) + Ah) = Bh  and	 ((-X7 + 12C) mod Ah) = 0
or  (U0' AND F) + Ah) = Ah  and	 ((-X7 + 12C) mod Ah) = 9
And so:
    (U0' AND F) + Ah = {Fh, Eh, Dh, Ch, Bh ,Ah}
<=> (U0' AND F)      = {5, 4, 3, 2, 1, 0}
<=> U0' = {35h, 34h, 33h, 32h, 31h, 30h}
The chars U0, U1, ..., U7 are compulsorily included between 30h and 35h. We use the same process for the second line (L2).

S0, S1, ..., S7 can contain the following chars: {"0", "1", "2", "3", "8", "9", ":", ";", "<", "="}. But with having a quick look at the first line (L1), we see that S0, S1, ..., S7 are the result of a mod Ah, so the chars S0, S1, ..., S7 are compulsorily one of this: {"0", "1", "2", "3", "8", "9"}

With these few restrictions, we can try to produce couple/pair (X0-X7, ..., X7-Xe). See my source written in C; for each 8 letters of the name, we will find couples.

Remark: The 8th character is used two times (couple X0-X7 and X7-Xe), so you should be careful. The 6 other couples can be taken as you want.
example: _123456_789abc_ (warning: the two couples X0-X7 and X7-Xe have X7 in commun!)

What is doing the source?
It computes possible couples for each letter of your name; by taking 8 couples it may work! Why it may: because my source assumes that there is no re-ordering/copy loop; X?=X?' et U?=U?'. (see in XXXX:004014AB et XXXX:004013C5). In my view, it is the easiest way to succeed this battle.

And then, we have to find couples which gives EDX=0 (other value of edx are possible) in XXXX:004013CC et XXXX:004014B8. In order not to change the order for X0, X1, ..., X7 (same thing for U0, U1, ..., U7).

How finding a valid serial?
Firstly, you must pass the first re-ordering/copy loop, for this, use your feeling, try to make the 8 first characters cyclic (example: 48484848), or with few times the same character. When you have passed the first re-ordering/copy loop, change the 7 last chars to pass the second (edx=0 in XXXX:004014AB; or edx=? if U0=U0', ..., U7=U7').

For my name, i take eight working couples:
0       2		;couple for the letter "L"
 0       X		;couple for the letter "u"
  0       8		;couple for the letter "c"
   4       8		;couple for the letter "i"
    1       8		;couple for the letter "f"
     0       9		;couple for the letter "e"
      4       X		;couple for the letter "r"
       e       n	;couple for the letter "4"
-----------------
0004104e2X8889Xn
You add to this serial a 16th char which is not used by the protection scheme, et you get few good serials (Name/ Lucifer48):

0004104e2X8889n*
0004104e2X8889d*
0004104e2X8889Z*
0004104e2X8889P*
0004104e2X8889F*

`004104e2X8889x*
...
`004104e2X8889F*

* any character

Status: registered!!


Battle Two: The Tower

XXXX:00401834  PUSH 004046E3				;address of buffer
XXXX:00401839  PUSH EAX					;length of serial -1 (see remark)
XXXX:0040183A  PUSH 0D					;WM_GETTEXT
XXXX:0040183C  PUSH 000000CB				;serial edit box
XXXX:00401841  PUSH DWORD PTR [EBP+08]			;handle of the dialog box
XXXX:00401844  CALL USER32!SendDlgItemMessageA
XXXX:00401849  CALL 0040168B				;protection scheme
XXXX:0040184E  CMP  BYTEP PTR [004044E0],01
XXXX:00401855  JNZ  0040187D				;jmp = bad serial
Remark: The last char (key) pressed is not read, because the buffer have the size of EAX (EAX is the length of the serial gotten with WM_GETTEXTLENGTH just before); in fact the length of buffer is EAX-1; the last byte is reserved because it is null; so we must add another char after the serial to get the good length. In my view, it is wanted by the author because the name is read correcly (XXXX:00401806 INC EAX).

Let's note X0, X1, ..., X9 the chars of the serial; and N0, N1, ..., N8 the chars of the name.
In the call 0040168B:
... (eax=ebx=ecx=edx=0)
XXXX:00401693  MOV  AL,[004046E3]			;X0
XXXX:00401698  XOR  AL,[004046EC]			;X9
XXXX:0040169E  XOR  AH,AL				;AL=AH
XXXX:004016A0  XOR  AX,[004046E4]			;X2 X1
XXXX:004016A7  XOR  EAX,[004046E6]			;X6 X5 X4 X3
XXXX:004016AD  XOR  EAX,[004046E8]			;X8 X7 X6 X5
XXXX:004016B3  XOR  EAX,[00404AE5]			;N3 N2 N1 N0
XXXX:004016B9  XOR  EAX,[00404AE8]			;N6 N5 N4 N3
XXXX:004016BF  XOR  AX,[00404AEC]			;N8 N7
XXXX:004016C6  MOV  ECX,EAX				;save the result for later use
XXXX:004016C8  MOV  EBX,00000029
XXXX:004016CD  CWD
XXXX:004016CF  IDIV EBX
XXXX:004016D1  MOV  EAX,EDX
XXXX:004016D3  MOV  EBX,00000009
XXXX:004016D8  CWD
XXXX:004016DA  IDIV EBX
XXXX:004016DC  MOV  EAX,EDX
So EAX= (EAX mod 41d) mod 9; we have 9 possibilities:
EAX=0: EAX = (ECX mod 7) + 1 et ECX = ECX XOR 00BC614E   (BC614Eh=12345678d)
EAX=1: ECX = ECX XOR 0023CACE		;23CACEh = 2345678d
EAX=2: ECX = ECX XOR 0005464E		; 5464Eh =  345678d
EAX=3: ECX = ECX XOR 0000B26E		;  B26Eh =   45678d
EAX=4: ECX = ECX XOR 0000162E		;  162Eh =    5678d
EAX=5: ECX = ECX XOR 000002A6		;   2A6h =     678d
EAX=6: ECX = ECX XOR 0000004E		;    4Eh =      78d
EAX=7: ECX = ECX XOR 00000008		;     8h =       8d
EAX=8: ECX = ECX XOR 00000000
If the name is not long enough, we can use the fact that the missing byte(s) is null (the buffer is long enough).
XXXX:00401743  CMP  EAX,36F95001
XXXX:00401749  SETZ AL
XXXX:0040174C  MOV  [004044E0],AL
XXXX:00401751  RET
So we conclude that in XXXX:004016C6, ecx mod 41d = { 36d, 27d, 18d, 9d, 0d }.
We execute the case EAX=0, to get a new value (between 1 to 8) of EAX.

And we will restart the same process as above, just after passed the case EAX=0.
Result to find: 36F95001 XOR 00BC614E = 3645314F
But before finding 3645314F, don't forget that we must pass the mod test (by having a null remainder). We see, there are two possibilities (stay 3 and 2; see above). Then:

I summarize:
- In XXXX:004016C6 i have ECX = 36407701
- (36407701h mod 41d) mod 9 = 0 (in eax)
- 36407701 XOR 00BC614E = 36FC164F (XXXX:004016FD)
- (36407701h mod 7) + 1 = 2
- I have ECX = 36FC164F (and EAX=2)
- 36FC164F XOR 5464Eh = 36F95001 (= result to find!!)
So the only possible dword (in XXXX:004016C6) is: 36407701. The following is very classical (found in many crackmes).

I remove (at first) the mask of my name ( 6963754Ch XOR 72656669h XOR 00003834 = 1B062B11 ).
36407701 XOR 1B062B11 = 2D465C10
It stays now to solve this:
	00 00 X0 X0
 xor    00 00 X9 X9
 xor	00 00 X2 X1
 xor	X6 X5 X4 X3
 xor	X8 X7 X6 X5
	-----------
	2D 46 5C 10
I take as example (i try to solve it simply):
X1=X9=X0= 30h ("0")
X3= 50h ("P")
X5= 70h ("p")

X4= 2Dh ("-")
X6= 41h ("A")
X2= 30h ("0")

X5 XOR 46 = X7 so X7= 36h ("6")
X6 XOR 2D = X8 so X8= 6Ch ("l")
By putting the chars together, we get the serial: 000P-pA6l0
You add a last dummy char; we get this:

Name/ Lucifer48
Serial/ 000P-pA6l0*

(* any character)

or better:
Serial/ #00P-pA6l#*
(* any character; # any character too)

There are many other possibilities...

Status: registered!!


The Final Battle: The Princess

XXXX:0040270D  CMP  BYTE PTR [004044E1],01	;good combination of the check boxes ?
XXXX:00402714  JNZ  00402748
XXXX:00402716  PUSH 00				;MB_OK
XXXX:00402718  PUSH 0040446D			;You have succeeded!
XXXX:0040271D  PUSH 004043D6			;end message
XXXX:00402722  PUSH DWORD PTR [EBP+08]		;handle
XXXX:00402725  CALL USER32!MessageBoxA
XXXX:0040272A  PUSH FF
XXXX:0040272C  PUSH DWORD PTR [EBP+08]
XXXX:0040272F  CALL USER32!EndDialog
XXXX:00402734  JMP  00402748
If we have put the check boxes correctly; then, [004044E1] is set to 1 (just before the crackme is checking if the edit box isn't empty) and then, a new dialog box is created, and you can see the princess in front of you. Wow !!!

The easiest combination is to press 1 single button:
  O O O O
 O o   o O
O   ___   O
 O       X   <------ this check box
  O O O O
XXXX:004011F8  CALL USER32!DialogBoxParamA	;dialog box of the crackme 3
XXXX:004011FD  CMP  BYTE PTR [004044E1],01	;see comment below
XXXX:00401204  JNZ  00401221
XXXX:00401206  MOV  EAX,004018B5
...
XXXX:00401216  PUSH DWORD PTR [004044D4]
XXXX:0040121C  CALL USER32!DialogBoxParamA	;display the princess
XXXX:00401221  JMP  004012D8
In fact, to arrive to the MessageBox, there is a patch to do:
XXXX:004026C7  CMP  AX,013F			;control ID of "OK"  button
XXXX:004026CB  JNZ  0040274A
XXXX:004026CD  SHR  EAX,10			;EAX=00000000
XXXX:004026D0  OR   AX,AX
XXXX:004026D3  JNZ  00402781			;ZF is set (no jump)
XXXX:004026D9  CMP  EAX,-01			;it's IMPOSSIBLE!!!
XXXX:004026DC  JNZ  00402736
Is that a allusion for: you cannot see the blade ???


Conclusion & Greetings

Finaly, i did it ! The first battle is really the most difficult. The second was ... classical; and the final battle: a little strange ! However, it was a bit tougher than ConquerMe I. Awaiting (maybe) ConquerMe III (coded in asm of course...); i salute you!

Greetings: All ID members (Volatility, Torn@do, ...), Eternal Bliss, ACiD BuRN, LaZaRuS, Duelist, people on #cracking4newbies, ..., and YOU MisterE for creating two excellent crackmes !!!



(c) Lucifer48. All rights reversed